﻿// ------------------------------------------------------------------------------------------------
//  <copyright file="Invert.cs" company="Iveely">
//    Copyright (c) Iveely Liu.  All rights reserved.
//  </copyright>
//  
//  <Create Time>
//    12/03/2012 20:12 
//  </Create Time>
//  
//  <contact owner>
//    liufanping@iveely.com 
//  </contact owner>
//  -----------------------------------------------------------------------------------------------

#region

using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using IveelySE.NLP.Common.DataStructure.Table;
using IveelySE.NLP.Segment;

#endregion

namespace IveelySE.NLP.Index
{
    /// <summary>
    ///   倒排索引建立
    /// </summary>
    [Serializable]
    public class Invert
    {
        #region 属性或字段

        /// <summary>
        ///   分词组件
        /// </summary>
        private readonly Participle participle;

        /// <summary>
        ///   倒排表
        /// </summary>
        //private ListTable<double> table;
        private readonly DimensionTable<string, string, double> table;

        #endregion

        #region 公有方法

        /// <summary>
        ///   构造方法
        /// </summary>
        public Invert()
        {
            this.table = new DimensionTable<string, string, double>();
            participle = Participle.GetInstance();
        }

        /// <summary>
        ///   添加文档
        ///   <example>
        ///     如果该文档编号已经存在则，覆盖以前的索引
        ///   </example>
        /// </summary>
        /// <param name="id"> 文档编号 </param>
        /// <param name="doc"> 文档内容 </param>
        public void AddDocument(object id, string doc, bool split = false)
        {
            // 获取此文档的词频集合
            string[] words;
            if (split)
            {
                words = doc.Split(' ');
            }
            else
            {
                words = participle.Split(doc).Split('/');
            }
            IntTable<string, int> frequency = this.GetFrequency(words);
            foreach (DictionaryEntry de in frequency)
            {
                this.table[de.Key.ToString()][id.ToString()] = de.Value;
            }
        }

    

        /// <summary>
        ///   根据关键字获取它所在地文档以及在文档中的频率
        ///   <example>
        ///     例如传入关键字：“北京”
        ///     传出结果：3.231 6.2145 9.542 ...
        ///     分别表示在文档231中，出现次数3
        ///     在文档2145中出现次数6
        ///     依次类推。
        ///   </example>
        /// </summary>
        /// <param name="key"> 关键字 </param>
        /// <param name="asc"> 是否为升序 </param>
        /// <returns> 返回按照频率的集合 </returns>
        public List<double> FindDocumentByKey(string key, bool asc)
        {
            return this.table.GetKeyValueByName(key);
        }

        /// <summary>
        ///   根据关键字集获取它所在地文档以及在文档中的频率
        ///   <example>
        ///     例如传入关键字：“北京 地铁”
        ///     会将二者对应的文档按照同时出现的情况进行合并
        ///   </example>
        /// </summary>
        /// <returns> 返回按照频率的集合 </returns>
        public IList<double> FindCommonDocumentByKeys(string[] keys)
        {
            var list = new DoubleIntTable();

            foreach (string key in keys)
            {
                List<double> result = this.FindDocumentByKey(key, false);
                list.AddItems(result);
            }

            return list.GetValuesBySort();
        }

        #endregion

        #region 私有方法

        /// <summary>
        ///   获取文档中关键字的频率
        /// </summary>
        /// <param name="words"> </param>
        /// <returns> </returns>
        private IntTable<string, int> GetFrequency(string[] words)
        {
            var frequerncy = new IntTable<string, int>();
            frequerncy.Add(words);
            return frequerncy;
        }

     

        #endregion

        #region 测试

        [Conditional("DEBUG")]
        public static void Test_FindDocumentByKey()
        {
            var invert = new Invert();
            invert.AddDocument(1, "今天天气真好");
            invert.AddDocument(2, "今天天气虽然很好，但是风大");
            invert.AddDocument(3, "天天就知道吃");
            invert.AddDocument(4, "爱是粉红的羽毛");
            invert.AddDocument(5, "雪白的羽毛");
            invert.AddDocument(6, "生活天很好");
            IList<double> result = invert.FindCommonDocumentByKeys(new[] { "爱", "风", "好" });
            foreach (var re in result)
            {
                Console.WriteLine(re);
            }
        }

        #endregion
    }
}